// Disable some Microsoft compiler warnings

#ifdef _MSC_VER
  #pragma warning (disable : 4996)
#endif


// Include platform specific headers

#ifdef _WIN32
  #include <windows.h>
#elif defined (LINUX)
  #include <X11/Xlib.h>
  #include <X11/Xutil.h>
  #include <X11/Xatom.h>
  #undef KeyPress
#else
  #include <Carbon/Carbon.h>
#endif


#include "SoundPotMainAudioEffect.h"

// Todo: Remove
#include "SoundPotTestInstrumentDao.h"

// Include VST interface

#include "public.sdk/source/vst2.x/audioeffectx.cpp"
#include "public.sdk/source/vst2.x/audioeffect.cpp"




// No idea

#ifdef PRAGMA_ALIGN_SUPPORTED
  #undef PRAGMA_ALIGN_SUPPORTED
  #define PRAGMA_ALIGN_SUPPORTED 1
#endif






// No idea

#undef MemoryBlock

// I don't dare to touch this. Maybe make non-static later or put at least into class definition.

static bool recursionCheck = false;
static uint32 lastMasterIdleCall = 0;


// No idea

namespace juce {

	extern void juce_callAnyTimersSynchronously();

	#if JUCE_MAC
	extern void juce_macDoPendingRepaintsNow();
	#elif JUCE_LINUX
	extern Display* display;
	extern bool juce_dispatchNextMessageOnSystemQueue (bool);
	#endif
}





SoundPot::MainAudioEffect::MainAudioEffect (audioMasterCallback audioMaster)
		   : AudioEffectX (audioMaster, 0, 0),
	#if JUCE_LINUX
			 Thread (T("VstEventThread")),
	#endif
			 numInputChannels (0),
			 numOutputChannels (32),
			 activeEditor (0)
{

	sampleRate = 0.0;
	blockSize = 0;

	lastUIWidth = 400;
	lastUIHeight = 140;

	setNumInputs(0);
	setNumOutputs(32);


	// editorComp = 0;
	outgoingEvents = 0;
	outgoingEventSize = 0;
	chunkMemoryTime = 0;
	isProcessing = false;
	hostWindow = 0;

	cEffect.flags |= effFlagsHasEditor;

	setUniqueID ((int) ('JcDm'));


	canProcessReplacing (true);

	isSynth (true);
	noTail (true);
	setInitialDelay (0);
	programsAreChunks (true);

	activePlugins.add (this);





	// Finally the real stuff can be made

	
	instrumentDao = new TestInstrumentDao();
	
	soundHost = new SoundHost(instrumentDao, this);
	
	soundHost->setMaxBlockSize(getMaxBlockSize());
	soundHost->setSampleRate(getSampleRate());
	
	sound1 = new VstSound();
	sound1->setInstrumentID("vstation");
	

	soundHost->addSound(sound1);





}

SoundPot::MainAudioEffect::~MainAudioEffect()
{
	delete sound1;
	delete soundHost;
	delete instrumentDao;
	
	stopTimer();
	deleteEditor();

	if (outgoingEvents != 0)
	{
		for (int i = outgoingEventSize; --i >= 0;)
			juce_free (outgoingEvents->events[i]);

		juce_free (outgoingEvents);
		outgoingEvents = 0;
	}

	// jassert (editorComp == 0);

	jassert (activePlugins.contains (this));
	activePlugins.removeValue (this);

#if JUCE_LINUX
	stopThread (1000);
#endif

#if JUCE_MAC || JUCE_LINUX
	if (activePlugins.size() == 0)
		shutdownJuce_GUI();
#endif
}

void SoundPot::MainAudioEffect::open()
{
#if JUCE_LINUX
	startThread (6);
#endif
	startTimer (1000 / 4);
}

void SoundPot::MainAudioEffect::close()
{
	jassert (! recursionCheck);

	stopTimer();
	deleteEditor();
}

bool SoundPot::MainAudioEffect::getEffectName (char* name)
{
	name = "SoundPot";
	return true;
}

bool SoundPot::MainAudioEffect::getVendorString (char* text)
{
	text = "Gandaland";
	return true;
}

bool SoundPot::MainAudioEffect::getProductString (char* text)
{
	return getEffectName (text);
}

VstInt32 SoundPot::MainAudioEffect::getVendorVersion()
{
	return 1000;
}

VstPlugCategory SoundPot::MainAudioEffect::getPlugCategory()
{
	return kPlugCategSynth;
}

VstInt32 SoundPot::MainAudioEffect::canDo (char* text)
{
	VstInt32 result = 0;

	if (strcmp (text, "receiveVstEvents") == 0 
		|| strcmp (text, "receiveVstMidiEvents") == 0)
	{
		result = 1;
	}
	else if (strcmp (text, "sendVstEvents") == 0
			 || strcmp (text, "sendVstMidiEvent") == 0)
	{
		result = 1;
	}
	else if (strcmp (text, "receiveVstTimeInfo") == 0)
	{
		result = 1;
	}
	else if (strcmp (text, "conformsToWindowRules") == 0)
	{
		result = 1;
	}

	return result;
}

bool SoundPot::MainAudioEffect::keysRequired()
{
	return false;
}

VstInt32 SoundPot::MainAudioEffect::processEvents (VstEvents* events)
{
	sound1->control(events);
	/*
	for (int i = 0; i < events->numEvents; ++i)
	{
		const VstEvent* const e = events->events[i];
		
		// Helgo: Later don't go long way over MidiBuffer
		if (e != 0 && e->type == kVstMidiType)
		{
			const VstMidiEvent* const vme = (const VstMidiEvent*) e;

			midiEvents.addEvent ((const uint8*) vme->midiData, 
								 4,
								 vme->deltaFrames);
		}
	}
	*/
	return 1;
}

void SoundPot::MainAudioEffect::processReplacing (float** inputs, float** outputs, VstInt32 numSamples)
{
	// if this fails, the host hasn't called resume() before processing
	// Helgo: direct
	jassert (isProcessing);

	// (tragically, some hosts actually need this, although it's stupid to have
	//  to do it here..)
	if (! isProcessing)
		resume();


	// Helgo: Maybe remove
	jassert (activePlugins.contains (this));

	{
		/*
		const AudioSampleBuffer input (inputs, filter->numInputChannels, numSamples);
		AudioSampleBuffer output (outputs, filter->numOutputChannels, numSamples);
		*/
		
		const ScopedLock sl (this->callbackLock);

		if (false) // (this->suspended)
		{
			// output.clear();
		}
		else
		{
			sound1->getAssignedInstrument()->fillNextAudioBlock(inputs, outputs, numSamples);
		}
	}

	if (! midiEvents.isEmpty())
	{
		const int numEvents = midiEvents.getNumEvents();

		ensureOutgoingEventSize (numEvents);
		outgoingEvents->numEvents = 0;

		const uint8* midiEventData;
		int midiEventSize, midiEventPosition;
		MidiBuffer::Iterator i (midiEvents);

		while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
		{
			if (midiEventSize <= 4)
			{
				VstMidiEvent* const vme = (VstMidiEvent*) outgoingEvents->events [outgoingEvents->numEvents++];

				memcpy (vme->midiData, midiEventData, midiEventSize);
				vme->deltaFrames = midiEventPosition;

				jassert (vme->deltaFrames >= 0 && vme->deltaFrames < numSamples);
			}
		}

		sendVstEventsToHost (outgoingEvents);
		midiEvents.clear();
	}

    /*    
	// if we're not accumulating, the output buffer's contents are undefined
        // (don't assume they're zero!) and we should overwrite it.

        if (input.getNumChannels() > 0)
        {
            for (int channel = 0; channel < output.getNumChannels(); ++channel)
            {
                // for each output channel, copy the contents of the corresponding
                // input channel (or if there are more outputs than inputs, just
                // keep using the last input channel)
                output.copyFrom (channel, 
                                 0, 
                                 input, 
                                 jmin (channel, input.getNumChannels() - 1),
                                 0, 
                                 input.getNumSamples());
            }

            output.applyGain (0, output.getNumSamples(), gain);
        }
        else
        {
            // when not accumulating, you always have to put something into
            // the output buffer, even if in this case we have no inputs to copy.
            output.clear();
        }
    }

    // if any midi messages come in, use them to update the keyboard state object. This
    // object sends notification to the UI component about key up/down changes
    keyboardState.processNextMidiBuffer (midiMessages, 
                                         0, output.getNumSamples(),
                                         true);
	*/

    // have a go at getting the current time from the host, and if it's changed, tell
    // our UI to update itself.
	CurrentPositionInfo pos;

    if (getCurrentPositionInfo (pos))
    {
        if (memcmp (&pos, &lastPosInfo, sizeof (pos)) != 0)	// If has changed
        {
            lastPosInfo = pos;
            sendChangeMessage (this);
        }
    }
    else
    {
        zeromem (&lastPosInfo, sizeof (lastPosInfo));
        lastPosInfo.timeSigNumerator = 4;
        lastPosInfo.timeSigDenominator = 4;
        lastPosInfo.bpm = 120;
    }
}



void SoundPot::MainAudioEffect::resume()
{
	isProcessing = true;

	this->sampleRate = getSampleRate();

	jassert (this->sampleRate > 0);

	if (this->sampleRate <= 0)
		this->sampleRate = 44100.0;
	
	this->blockSize = getBlockSize();
	jassert (this->blockSize > 0);
	
	// Prepare to play here, load resources!!!!

	midiEvents.clear();
	
	AudioEffectX::resume();

	ensureOutgoingEventSize (64);

}

void SoundPot::MainAudioEffect::suspend()
{
	AudioEffectX::suspend();

	// Release Resources here!!!

	midiEvents.clear();

	isProcessing = false;
}


bool JUCE_CALLTYPE SoundPot::MainAudioEffect::getCurrentPositionInfo (CurrentPositionInfo& info)
{
	const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid
											   | kVstTempoValid
											   | kVstBarsValid
											   //| kVstCyclePosValid
											   | kVstTimeSigValid
											   | kVstSmpteValid
											   | kVstClockValid);

	if (ti == 0 || ti->sampleRate <= 0)
		return false;

	if ((ti->flags & kVstTempoValid) != 0)
		info.bpm = ti->tempo;
	else
		info.bpm = 0.0;

	if ((ti->flags & kVstTimeSigValid) != 0)
	{
		info.timeSigNumerator = ti->timeSigNumerator;
		info.timeSigDenominator = ti->timeSigDenominator;
	}
	else
	{
		info.timeSigNumerator = 4;
		info.timeSigDenominator = 4;
	}

	info.timeInSeconds = ti->samplePos / ti->sampleRate;

	if ((ti->flags & kVstPpqPosValid) != 0)
		info.ppqPosition = ti->ppqPos;
	else
		info.ppqPosition = 0.0;

	if ((ti->flags & kVstBarsValid) != 0)
		info.ppqPositionOfLastBarStart = ti->barStartPos;
	else
		info.ppqPositionOfLastBarStart = 0.0;

	if ((ti->flags & kVstSmpteValid) != 0)
	{
		info.frameRate = (CurrentPositionInfo::FrameRateType) (int) ti->smpteFrameRate;

		const double fpsDivisors[] = { 24.0, 25.0, 30.0, 30.0, 30.0, 30.0, 1.0 };
		info.editOriginTime = (ti->smpteOffset / (80.0 * fpsDivisors [(int) info.frameRate]));
	}
	else
	{
		info.frameRate = CurrentPositionInfo::fpsUnknown;
		info.editOriginTime = 0;
	}

	info.isRecording = (ti->flags & kVstTransportRecording) != 0;
	info.isPlaying   = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording;

	return true;
}



VstInt32 SoundPot::MainAudioEffect::getProgram()
{
	return 0;
}

void SoundPot::MainAudioEffect::setProgram (VstInt32 program)
{
}

void SoundPot::MainAudioEffect::setProgramName (char* name)
{
}

void SoundPot::MainAudioEffect::getProgramName (char* name)
{
	name = "Fuck you!";
}

bool SoundPot::MainAudioEffect::getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text)
{
	text = "Fuck you once again!";

	return true;
}

float SoundPot::MainAudioEffect::getParameter (VstInt32 index)
{
	return 0;
}

void SoundPot::MainAudioEffect::setParameter (VstInt32 index, float value)
{

}

void SoundPot::MainAudioEffect::getParameterDisplay (VstInt32 index, char* text)
{

}

void SoundPot::MainAudioEffect::getParameterName (VstInt32 index, char* text)
{

}


VstInt32 SoundPot::MainAudioEffect::getChunk (void** data, bool isPreset)
{
	chunkMemory.setSize (0);

	// Write current state to chunkMemory here, maybe as XML!!!

	*data = (void*) chunkMemory;

	// because the chunk is only needed temporarily by the host (or at least you'd
	// hope so) we'll give it a while and then free it in the timer callback.
	chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter();

	return chunkMemory.getSize();
}

VstInt32 SoundPot::MainAudioEffect::setChunk (void* data, VstInt32 byteSize, bool isPreset)
{
	chunkMemory.setSize (0);
	chunkMemoryTime = 0;

	// Read current state here and restore things!!!

	return 0;
}
		
// This is called regularly by Timer thread (right?) - always try idle, sometimes chunkMemory gets cleared.

void SoundPot::MainAudioEffect::timerCallback()
{
	if (chunkMemoryTime > 0 
		&& chunkMemoryTime < juce::Time::getApproximateMillisecondCounter() - 2000
		&& ! recursionCheck)
	{
		chunkMemoryTime = 0;
		chunkMemory.setSize (0);
	}

	tryMasterIdle();
}

void SoundPot::MainAudioEffect::tryMasterIdle()
{
	if (Component::isMouseButtonDownAnywhere()
		 && ! recursionCheck)
	{
		const uint32 now = juce::Time::getMillisecondCounter();

		if (now > lastMasterIdleCall + 20 && activeEditor != 0) // Helgo: Replaced editorComp by activeEditor
		{
			lastMasterIdleCall = now;

			recursionCheck = true;
			masterIdle();
			recursionCheck = false;
		}
	}
}

void SoundPot::MainAudioEffect::doIdleCallback()
{
	if (! recursionCheck)
	{
		const MessageManagerLock mml;

		recursionCheck = true;

		juce_callAnyTimersSynchronously();

		for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
			ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow();

		recursionCheck = false;
	}
}

#if JUCE_LINUX
void SoundPot::MainAudioEffect::run ()
{
	MessageManager* messageManager = MessageManager::getInstance();
	int oldThreadId = messageManager->getCurrentMessageThread();
	messageManager->setCurrentMessageThread (Thread::getCurrentThreadId());

	int maxNumberOfMessagesToDispatch;

	while (! threadShouldExit())
	{
		maxNumberOfMessagesToDispatch = 10000;

		while (--maxNumberOfMessagesToDispatch >= 0
			   && ! threadShouldExit())
		{
			bool carryOn = false;
			try
			{
				carryOn = juce_dispatchNextMessageOnSystemQueue (true);
			}
			catch (...)
			{
			}

			if (! carryOn)
				break;
		}
	}

	messageManager->setCurrentMessageThread (oldThreadId);
}
#endif

void SoundPot::MainAudioEffect::deleteEditor()
{
	jassert (! recursionCheck);
	recursionCheck = true;

	Component* modalComponent = Component::getCurrentlyModalComponent();
	if (modalComponent != 0)
		modalComponent->exitModalState (0);

	if (activeEditor != 0) // Helgo: Replaced editorComp by activeEditor
	{

		// MainGui* editor = editorComp->getEditorComp();
		// MainGui* editor = editorComp;

		const ScopedLock sl (callbackLock);

		// jassert (activeEditor == editor);

		// if (activeEditor == editor)
		// activeEditor = 0;

		deleteAndZero (activeEditor); // Helgo: Replaced editorComp by activeEditor
	}

#if JUCE_MAC || JUCE_LINUX
	hostWindow = 0;
#endif

	recursionCheck = false;

	// there's some kind of component currently modal, but the host
	// is trying to delete our plugin. You should try to avoid this happening..
	jassert (Component::getCurrentlyModalComponent() == 0);
}


SoundPot::MainGui* SoundPot::MainAudioEffect::createEditor()
{
	return new MainGui (this);
}


void SoundPot::MainAudioEffect::createEditorComp()
{
	if (activeEditor == 0) // Helgo
	{
		MainGui* ed;

		// ............
		if (activeEditor != 0)
			ed = activeEditor;
		else
		{
			ed = createEditor();

			if (ed != 0)
			{
				// you must give your editor comp a size before returning it..
				jassert (ed->getWidth() > 0 && ed->getHeight() > 0);

				const ScopedLock sl (callbackLock);
				activeEditor = ed;
			}
		}
		// ..............




		if (ed != 0)
		{
			ed->setOpaque (true);
			ed->setVisible (true);

			// editorComp = new EditorCompWrapper (this, ed);
			// editorComp = ed;
		}
	}
}

VstIntPtr SoundPot::MainAudioEffect::dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt)
{
	if (opCode == effEditIdle)
	{
		doIdleCallback();
		return 0;
	}
	else if (opCode == effEditOpen)
	{
		jassert (! recursionCheck);

		deleteEditor();
		createEditorComp();

		if (activeEditor != 0) // Helgo: Replaced editorComp by activeEditor
		{
#if JUCE_LINUX
			const MessageManagerLock mml;
#endif

			activeEditor->setOpaque (true); // Helgo: Replaced editorComp by activeEditor
			activeEditor->setVisible (false); // Helgo: Replaced editorComp by activeEditor

#if JUCE_WIN32
			activeEditor->addToDesktop (0); // Helgo: Replaced editorComp by activeEditor

			hostWindow = (HWND) ptr;
			HWND editorWnd = (HWND) activeEditor->getWindowHandle(); // Helgo: Replaced editorComp by activeEditor

			SetParent (editorWnd, hostWindow);

			DWORD val = GetWindowLong (editorWnd, GWL_STYLE);
			val = (val & ~WS_POPUP) | WS_CHILD;
			SetWindowLong (editorWnd, GWL_STYLE, val);

			activeEditor->setVisible (true); // Helgo: Replaced editorComp by activeEditor
#elif JUCE_LINUX
			activeEditor->addToDesktop (0); // Helgo: Replaced editorComp by activeEditor

			hostWindow = (Window) ptr;

			Window editorWnd = (Window) activeEditor->getWindowHandle(); // Helgo: Replaced editorComp by activeEditor

			XReparentWindow (display, editorWnd, hostWindow, 0, 0);

			activeEditor->setVisible (true); // Helgo: Replaced editorComp by activeEditor
#else
			hostWindow = (WindowRef) ptr;

			SetAutomaticControlDragTrackingEnabledForWindow (hostWindow, true);

			WindowAttributes attributes;
			GetWindowAttributes (hostWindow, &attributes);

			HIViewRef parentView = 0;

			if ((attributes & kWindowCompositingAttribute) != 0)
			{
				HIViewRef root = HIViewGetRoot (hostWindow);
				HIViewFindByID (root, kHIViewWindowContentID, &parentView);

				if (parentView == 0)
					parentView = root;
			}
			else
			{
				GetRootControl (hostWindow, (ControlRef*) &parentView);

				if (parentView == 0)
					CreateRootControl (hostWindow, (ControlRef*) &parentView);
			}

			jassert (parentView != 0); // agh - the host has to provide a compositing window..

			activeEditor->setVisible (true); // Helgo: Replaced editorComp by activeEditor
			activeEditor->addToDesktop (0, (void*) parentView); // Helgo: Replaced editorComp by activeEditor
#endif

			return 1;
		}
	}
	else if (opCode == effEditClose)
	{
		deleteEditor();
		return 0;
	}
	else if (opCode == effEditGetRect)
	{
		
		
		// Todo: Remove
		sound1->showEditor();
		
		createEditorComp();



		if (activeEditor != 0) // Helgo: Replaced editorComp by activeEditor
		{
			editorSize.left = 0;
			editorSize.top = 0;
			editorSize.right = activeEditor->getWidth(); // Helgo: Replaced editorComp by activeEditor
			editorSize.bottom = activeEditor->getHeight(); // Helgo: Replaced editorComp by activeEditor

			*((ERect**) ptr) = &editorSize;

			return (VstIntPtr) &editorSize;
		}
		else
		{
			return 0;
		}
	}
#if defined (JUCE_LINUX)
	else if (opCode == effSetSampleRate)
	{
		setSampleRate ((int) opt);
		return 0;
	}
	else if (opCode == effProcessEvents)
	{
		if (ptr != 0)
			return processEvents ((VstEvents*) ptr);

		return 1;
	}
#endif

	// Necessary to call new VST SDK methods
	return AudioEffectX::dispatcher (opCode, index, value, ptr, opt);
}

void SoundPot::MainAudioEffect::resizeHostWindow (int newWidth, int newHeight)
{
	if (activeEditor != 0) // Helgo: Replaced editorComp by activeEditor
	{
		int u = canHostDo("sizeWindow");
		if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight)))
		{
			// some hosts don't support the sizeWindow call, so do it manually..
#if JUCE_MAC
			Rect r;
			GetWindowBounds (hostWindow, kWindowContentRgn, &r);

			r.right += newWidth - activeEditor->getWidth(); // Helgo: Replaced editorComp by activeEditor
			r.bottom += newHeight - activeEditor->getHeight(); // Helgo: Replaced editorComp by activeEditor

			SetWindowBounds (hostWindow, kWindowContentRgn, &r);
            
			r.bottom -= r.top;
			r.right -= r.left;
			r.left = r.top = 0;
			InvalWindowRect (hostWindow, &r);
#elif JUCE_LINUX
			// xxx
			XResizeWindow (display, hostWindow, newWidth, newHeight);
#else
			int dw = 0;
			int dh = 0;
			const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME);

			HWND w = (HWND) activeEditor->getWindowHandle(); // Helgo: Replaced editorComp by activeEditor

			while (w != 0)
			{
				HWND parent = GetParent (w);

				if (parent == 0)
					break;

				TCHAR windowType [32];
				zeromem (windowType, sizeof (windowType));
				GetClassName (parent, windowType, 31);

				if (String (windowType).equalsIgnoreCase (T("MDIClient")))
					break;

				RECT windowPos;
				GetWindowRect (w, &windowPos);

				RECT parentPos;
				GetWindowRect (parent, &parentPos);

				SetWindowPos (w, 0, 0, 0, 
							  newWidth + dw, 
							  newHeight + dh,
							  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);

				dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left);
				dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top);

				w = parent;

				if (dw == 2 * frameThickness)
					break;

				if (dw > 100 || dh > 100)
					w = 0;
			}

			if (w != 0)
				SetWindowPos (w, 0, 0, 0, 
							  newWidth + dw, 
							  newHeight + dh,
							  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
#endif
		}

		if (activeEditor->getPeer() != 0) // Helgo: Replaced editorComp by activeEditor
			activeEditor->getPeer()->handleMovedOrResized(); // Helgo: Replaced editorComp by activeEditor
	}
}

void SoundPot::MainAudioEffect::ensureOutgoingEventSize (int numEvents)
{
	if (outgoingEventSize < numEvents)
	{
		numEvents += 32;
		const int size = 16 + sizeof (VstEvent*) * numEvents;

		if (outgoingEvents == 0)
			outgoingEvents = (VstEvents*) juce_calloc (size);
		else
			outgoingEvents = (VstEvents*) juce_realloc (outgoingEvents, size);

		for (int i = outgoingEventSize; i < numEvents; ++i)
		{
			VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (sizeof (VstMidiEvent));
			e->type = kVstMidiType;
			e->byteSize = 24;

			outgoingEvents->events[i] = (VstEvent*) e;
		}

		outgoingEventSize = numEvents;
	}
}

const String SoundPot::MainAudioEffect::getHostName()
{
	char host[256];
	zeromem (host, sizeof (host));
	getHostProductString (host);
	return host;
}

float SoundPot::MainAudioEffect::getCurrentSampleRate()
{
	return getSampleRate();
}

int SoundPot::MainAudioEffect::getMaxBlockSize()
{
	return getBlockSize();
}



